@@ -208,6 +208,10 @@ class Agent < ActiveRecord::Base |
||
| 208 | 208 |
self.class.can_dry_run? |
| 209 | 209 |
end |
| 210 | 210 |
|
| 211 |
+ def no_bulk_receive? |
|
| 212 |
+ self.class.no_bulk_receive? |
|
| 213 |
+ end |
|
| 214 |
+ |
|
| 211 | 215 |
def log(message, options = {})
|
| 212 | 216 |
AgentLog.log_for_agent(self, message, options) |
| 213 | 217 |
end |
@@ -350,6 +354,14 @@ class Agent < ActiveRecord::Base |
||
| 350 | 354 |
!!@can_dry_run |
| 351 | 355 |
end |
| 352 | 356 |
|
| 357 |
+ def no_bulk_receive! |
|
| 358 |
+ @no_bulk_receive = true |
|
| 359 |
+ end |
|
| 360 |
+ |
|
| 361 |
+ def no_bulk_receive? |
|
| 362 |
+ !!@no_bulk_receive |
|
| 363 |
+ end |
|
| 364 |
+ |
|
| 353 | 365 |
def gem_dependency_check |
| 354 | 366 |
@gem_dependencies_checked = true |
| 355 | 367 |
@gem_dependencies_met = yield |
@@ -365,7 +377,7 @@ class Agent < ActiveRecord::Base |
||
| 365 | 377 |
def receive!(options={})
|
| 366 | 378 |
Agent.transaction do |
| 367 | 379 |
scope = Agent. |
| 368 |
- select("agents.id AS receiver_agent_id, sources.id AS source_agent_id, events.id AS event_id").
|
|
| 380 |
+ select("agents.id AS receiver_agent_id, events.id AS event_id").
|
|
| 369 | 381 |
joins("JOIN links ON (links.receiver_id = agents.id)").
|
| 370 | 382 |
joins("JOIN agents AS sources ON (links.source_id = sources.id)").
|
| 371 | 383 |
joins("JOIN events ON (events.agent_id = sources.id AND events.id > links.event_id_at_creation)").
|
@@ -377,21 +389,25 @@ class Agent < ActiveRecord::Base |
||
| 377 | 389 |
sql = scope.to_sql() |
| 378 | 390 |
|
| 379 | 391 |
agents_to_events = {}
|
| 380 |
- Agent.connection.select_rows(sql).each do |receiver_agent_id, source_agent_id, event_id| |
|
| 392 |
+ Agent.connection.select_rows(sql).each do |receiver_agent_id, event_id| |
|
| 381 | 393 |
agents_to_events[receiver_agent_id.to_i] ||= [] |
| 382 | 394 |
agents_to_events[receiver_agent_id.to_i] << event_id |
| 383 | 395 |
end |
| 384 | 396 |
|
| 385 |
- event_ids = agents_to_events.values.flatten.uniq.compact |
|
| 386 |
- |
|
| 387 | 397 |
Agent.where(:id => agents_to_events.keys).each do |agent| |
| 398 |
+ event_ids = agents_to_events[agent.id].uniq |
|
| 388 | 399 |
agent.update_attribute :last_checked_event_id, event_ids.max |
| 389 |
- Agent.async_receive(agent.id, agents_to_events[agent.id].uniq) |
|
| 400 |
+ |
|
| 401 |
+ if agent.no_bulk_receive? |
|
| 402 |
+ event_ids.each { |event_id| Agent.async_receive(agent.id, [event_id]) }
|
|
| 403 |
+ else |
|
| 404 |
+ Agent.async_receive(agent.id, event_ids) |
|
| 405 |
+ end |
|
| 390 | 406 |
end |
| 391 | 407 |
|
| 392 | 408 |
{
|
| 393 | 409 |
:agent_count => agents_to_events.keys.length, |
| 394 |
- :event_count => event_ids.length |
|
| 410 |
+ :event_count => agents_to_events.values.flatten.uniq.compact.length |
|
| 395 | 411 |
} |
| 396 | 412 |
end |
| 397 | 413 |
end |
@@ -2,6 +2,7 @@ module Agents |
||
| 2 | 2 |
class BeeperAgent < Agent |
| 3 | 3 |
cannot_be_scheduled! |
| 4 | 4 |
cannot_create_events! |
| 5 |
+ no_bulk_receive! |
|
| 5 | 6 |
|
| 6 | 7 |
description <<-MD |
| 7 | 8 |
Beeper agent sends messages to Beeper app on your mobile device via Push notifications. |
@@ -3,6 +3,7 @@ module Agents |
||
| 3 | 3 |
include DropboxConcern |
| 4 | 4 |
|
| 5 | 5 |
cannot_be_scheduled! |
| 6 |
+ no_bulk_receive! |
|
| 6 | 7 |
|
| 7 | 8 |
description <<-MD |
| 8 | 9 |
The Dropbox File Url Agent is used to work with Dropbox. It takes a file path (or multiple file paths) and emits events with [temporary links](https://www.dropbox.com/developers/core/docs#media). |
@@ -4,6 +4,7 @@ module Agents |
||
| 4 | 4 |
|
| 5 | 5 |
cannot_be_scheduled! |
| 6 | 6 |
cannot_create_events! |
| 7 |
+ no_bulk_receive! |
|
| 7 | 8 |
|
| 8 | 9 |
description <<-MD |
| 9 | 10 |
The Email Agent sends any events it receives via email immediately. |
@@ -3,6 +3,7 @@ require 'json' |
||
| 3 | 3 |
module Agents |
| 4 | 4 |
class GoogleCalendarPublishAgent < Agent |
| 5 | 5 |
cannot_be_scheduled! |
| 6 |
+ no_bulk_receive! |
|
| 6 | 7 |
|
| 7 | 8 |
gem_dependency_check { defined?(Google) && defined?(Google::APIClient) }
|
| 8 | 9 |
|
@@ -4,6 +4,7 @@ module Agents |
||
| 4 | 4 |
|
| 5 | 5 |
cannot_be_scheduled! |
| 6 | 6 |
cannot_create_events! |
| 7 |
+ no_bulk_receive! |
|
| 7 | 8 |
|
| 8 | 9 |
gem_dependency_check { defined?(HipChat) }
|
| 9 | 10 |
|
@@ -7,6 +7,7 @@ module Agents |
||
| 7 | 7 |
gem_dependency_check { defined?(HyPDF) }
|
| 8 | 8 |
|
| 9 | 9 |
cannot_be_scheduled! |
| 10 |
+ no_bulk_receive! |
|
| 10 | 11 |
|
| 11 | 12 |
description <<-MD |
| 12 | 13 |
The PDF Info Agent returns the metadata contained within a given PDF file, using HyPDF. |
@@ -3,6 +3,7 @@ module Agents |
||
| 3 | 3 |
include WebRequestConcern |
| 4 | 4 |
|
| 5 | 5 |
can_dry_run! |
| 6 |
+ no_bulk_receive! |
|
| 6 | 7 |
default_schedule "never" |
| 7 | 8 |
|
| 8 | 9 |
description <<-MD |
@@ -4,6 +4,7 @@ module Agents |
||
| 4 | 4 |
|
| 5 | 5 |
cannot_be_scheduled! |
| 6 | 6 |
cannot_create_events! |
| 7 |
+ no_bulk_receive! |
|
| 7 | 8 |
|
| 8 | 9 |
before_validation :create_device, on: :create |
| 9 | 10 |
|
@@ -2,6 +2,8 @@ module Agents |
||
| 2 | 2 |
class PushoverAgent < Agent |
| 3 | 3 |
cannot_be_scheduled! |
| 4 | 4 |
cannot_create_events! |
| 5 |
+ no_bulk_receive! |
|
| 6 |
+ |
|
| 5 | 7 |
|
| 6 | 8 |
API_URL = 'https://api.pushover.net/1/messages.json' |
| 7 | 9 |
|
@@ -3,6 +3,8 @@ module Agents |
||
| 3 | 3 |
default_schedule "never" |
| 4 | 4 |
|
| 5 | 5 |
can_dry_run! |
| 6 |
+ no_bulk_receive! |
|
| 7 |
+ |
|
| 6 | 8 |
|
| 7 | 9 |
def self.should_run? |
| 8 | 10 |
ENV['ENABLE_INSECURE_AGENTS'] == "true" |
@@ -5,6 +5,7 @@ module Agents |
||
| 5 | 5 |
|
| 6 | 6 |
cannot_be_scheduled! |
| 7 | 7 |
cannot_create_events! |
| 8 |
+ no_bulk_receive! |
|
| 8 | 9 |
|
| 9 | 10 |
gem_dependency_check { defined?(Slack) }
|
| 10 | 11 |
|
@@ -4,6 +4,7 @@ module Agents |
||
| 4 | 4 |
class TwilioAgent < Agent |
| 5 | 5 |
cannot_be_scheduled! |
| 6 | 6 |
cannot_create_events! |
| 7 |
+ no_bulk_receive! |
|
| 7 | 8 |
|
| 8 | 9 |
gem_dependency_check { defined?(Twilio) }
|
| 9 | 10 |
|
@@ -7,6 +7,7 @@ module Agents |
||
| 7 | 7 |
|
| 8 | 8 |
can_dry_run! |
| 9 | 9 |
can_order_created_events! |
| 10 |
+ no_bulk_receive! |
|
| 10 | 11 |
|
| 11 | 12 |
default_schedule "every_12h" |
| 12 | 13 |
|
@@ -1,6 +1,7 @@ |
||
| 1 | 1 |
module Agents |
| 2 | 2 |
class WitaiAgent < Agent |
| 3 | 3 |
cannot_be_scheduled! |
| 4 |
+ no_bulk_receive! |
|
| 4 | 5 |
|
| 5 | 6 |
description <<-MD |
| 6 | 7 |
The `wit.ai` agent receives events, sends a text query to your `wit.ai` instance and generates outcome events. |
@@ -5,6 +5,7 @@ module Agents |
||
| 5 | 5 |
valid_oauth_providers :wunderlist |
| 6 | 6 |
|
| 7 | 7 |
cannot_be_scheduled! |
| 8 |
+ no_bulk_receive! |
|
| 8 | 9 |
|
| 9 | 10 |
gem_dependency_check { Devise.omniauth_providers.include?(:wunderlist) }
|
| 10 | 11 |
|
@@ -56,7 +56,7 @@ describe HuginnScheduler do |
||
| 56 | 56 |
end |
| 57 | 57 |
end |
| 58 | 58 |
|
| 59 |
- describe "cleanup_failed_jobs!", focus: true do |
|
| 59 |
+ describe "cleanup_failed_jobs!" do |
|
| 60 | 60 |
before do |
| 61 | 61 |
3.times do |i| |
| 62 | 62 |
Delayed::Job.create(failed_at: Time.now - i.minutes) |
@@ -64,7 +64,7 @@ describe HuginnScheduler do |
||
| 64 | 64 |
@keep = Delayed::Job.order(:failed_at)[1] |
| 65 | 65 |
end |
| 66 | 66 |
|
| 67 |
- it "work with set FAILED_JOBS_TO_KEEP env variable", focus: true do |
|
| 67 |
+ it "work with set FAILED_JOBS_TO_KEEP env variable" do |
|
| 68 | 68 |
expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(-1)
|
| 69 | 69 |
expect { @scheduler.send(:cleanup_failed_jobs!) }.to change(Delayed::Job, :count).by(0)
|
| 70 | 70 |
expect(@keep.id).to eq(Delayed::Job.order(:failed_at)[0].id) |
@@ -295,6 +295,14 @@ describe Agent do |
||
| 295 | 295 |
Agent.receive! |
| 296 | 296 |
end |
| 297 | 297 |
|
| 298 |
+ it "should call receive for each event when no_bulk_receive! is used" do |
|
| 299 |
+ mock.any_instance_of(Agents::TriggerAgent).receive(anything).twice |
|
| 300 |
+ stub(Agents::TriggerAgent).no_bulk_receive? { true }
|
|
| 301 |
+ Agent.async_check(agents(:bob_weather_agent).id) |
|
| 302 |
+ Agent.async_check(agents(:bob_weather_agent).id) |
|
| 303 |
+ Agent.receive! |
|
| 304 |
+ end |
|
| 305 |
+ |
|
| 298 | 306 |
it "should ignore events that were created before a particular Link" do |
| 299 | 307 |
agent2 = Agents::SomethingSource.new(:name => "something") |
| 300 | 308 |
agent2.user = users(:bob) |
@@ -50,6 +50,13 @@ RSpec.configure do |config| |
||
| 50 | 50 |
# rspec-rails. |
| 51 | 51 |
config.infer_base_class_for_anonymous_controllers = false |
| 52 | 52 |
|
| 53 |
+ # These two settings work together to allow you to limit a spec run |
|
| 54 |
+ # to individual examples or groups you care about by tagging them with |
|
| 55 |
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples |
|
| 56 |
+ # get run. |
|
| 57 |
+ config.filter_run :focus |
|
| 58 |
+ config.run_all_when_everything_filtered = true |
|
| 59 |
+ |
|
| 53 | 60 |
# Run specs in random order to surface order dependencies. If you find an |
| 54 | 61 |
# order dependency and want to debug it, you can fix the order by providing |
| 55 | 62 |
# the seed, which is printed after each run. |
@@ -30,7 +30,7 @@ shared_examples_for LiquidInterpolatable do |
||
| 30 | 30 |
}) |
| 31 | 31 |
end |
| 32 | 32 |
|
| 33 |
- it "should work with arrays", focus: true do |
|
| 33 |
+ it "should work with arrays" do |
|
| 34 | 34 |
@checker.options = {"value" => ["{{variable}}", "Much array", "Hey, {{hello_world}}"]}
|
| 35 | 35 |
expect(@checker.interpolate_options(@checker.options, @event)).to eq({
|
| 36 | 36 |
"value" => ["hello", "Much array", "Hey, Hello world"] |